package com.grad.webstudy.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.grad.webstudy.constants.RedisConstants;
import com.grad.webstudy.context.UserContext;
import com.grad.webstudy.dao.CourseDao;
import com.grad.webstudy.dto.CourseDto;
import com.grad.webstudy.enums.CourseLevelEnums;
import com.grad.webstudy.enums.ExceptionEnums;
import com.grad.webstudy.enums.ObjTypeEnums;
import com.grad.webstudy.enums.StatusEnums;
import com.grad.webstudy.exceptions.CustomException;
import com.grad.webstudy.model.*;
import com.grad.webstudy.model.es.ESCourse;
import com.grad.webstudy.service.*;
import com.grad.webstudy.utils.RedisUtil;
import com.grad.webstudy.vo.CourseChapterVo;
import com.grad.webstudy.vo.CourseVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: zjf
 * @Date: 2020/2/6 14:40.
 */


@Service
@Transactional
public class CourseServiceImpl implements CourseService {


    @Autowired
    private CourseDao courseDao;


    @Autowired
    private CourseTypeService courseTypeService;


    @Autowired
    private CourseDetailService courseDetailService;


    @Autowired
    private CourseChapterService courseChapterService;


    @Autowired
    private ApplyService applyService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ElasticSearchService elasticSearchService;


    @Autowired
    private HistoryService historyService;


    @Override
    public int addCourse(Course course) {

        User loginUser = UserContext.getLoginUser();
        course.setScore(Float.valueOf(5));//设置初始分数为5
        course.setStudyNumber((int) (Math.random()*500+100));//100-500之间的学习人数
        course.setScoreUser(0);//设置初始打分人数为0
        course.setStatus(StatusEnums.AUDITING.getStatus());
        course.setTeacher(loginUser.getUsername());
        course.setCreateTime(new Date());

        String typeIds = course.getTypeId();

        course.setTypeId(stringConvert(typeIds));

        if (courseDao.insert(course) > 0) {
            applyService.addApply(ObjTypeEnums.COURSE.getObjType(), course.getId(), null);
        }
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return course.getId();
    }

    @Override
    public boolean deleteCourses(String ids) {
        List<String> deleteIds = Arrays.asList(ids.split(","));
        if (deleteIds.size() <= 0) {
            throw new CustomException(ExceptionEnums.CUSTOM_ERROR.getCode(),
                    "参数ids[" + ids + "]异常");
        }

        for (String deleteId : deleteIds) {
            elasticSearchService.deleteESCourse(deleteId);
            courseChapterService.deleteChaptersByCourseId(Integer.valueOf(deleteId));
        }
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return (courseDao.deleteCourses(deleteIds) == deleteIds.size()) && applyService.updateStatusForDelete(deleteIds, ObjTypeEnums.COURSE.getObjType());
    }

    @Override
    public boolean updateCourseInfo(CourseDto courseDto) {
        User loginUser = UserContext.getLoginUser();
        courseDto.setTeacher(loginUser.getUsername());

        String typeIds = courseDto.getTypeId();

        courseDto.setTypeId(stringConvert(typeIds));
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return courseDao.updateCourseInfo(courseDto) > 0;
    }

    /**
     * 将父分类添加进入结果中
     *
     * @param typeIds
     * @return
     */
    private String stringConvert(String typeIds) {
        List<String> typeIdList = Arrays.asList(typeIds.split(","));

        Set<Integer> parentIdSet = new HashSet<>();
        for (String typeId : typeIdList) {
            parentIdSet.add(courseTypeService.queryParentId(Integer.parseInt(typeId)));
        }
        for (Integer integer : parentIdSet) {
            typeIds += "," + integer;
        }
        return typeIds;
    }


    @Override
    public boolean changeCourseStatus(Integer id, Integer status) {
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return courseDao.changeCourseStatus(id, status) > 0;
    }

    @Override
    public boolean updateStudyNumber(Integer id) {
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return courseDao.updateStudyNumber(id) > 0;
    }

    @Override
    public boolean updateScore(Integer id, Float score) {
        Map<Integer, Float> result = courseDao.getRatingNumberAndScore(id);
        Integer studyNumber = 0;
        Float queryScore = Float.valueOf(0);

        for (Integer integer : result.keySet()) {
            studyNumber = integer;
            queryScore = result.get(studyNumber);
        }
        score = (queryScore * studyNumber + score) / (studyNumber + 1);
        redisUtil.delByPrefix(RedisConstants.REDIS_COURSE_KEY_PREFIX);

        return courseDao.updateScoreAndNumber(id, score) > 0;
    }

    @Override
    public PageInfo queryAllByPage(int currPage,
                                   int pageSize,
                                   Integer status, Integer level, Integer typeId, String keyword) {


        validStatus(status);
        String key = RedisConstants.REDIS_COURSE_KEY_PREFIX + "queryAll" +
                currPage + "-" + pageSize + "-" + status + "-" + level + "-" + typeId + "-" + keyword;

        PageInfo<CourseVo> result;
        if (redisUtil.hasKey(key)) {
            result = (PageInfo<CourseVo>) redisUtil.get(key);
        } else {
            Page page = PageHelper.startPage(currPage, pageSize);
            List<Course> courseTypes = courseDao.queryAll(status, level, typeId, keyword);
            result = new PageInfo<>(transToVo(courseTypes));

            result.setTotal(page.getTotal());
            result.setPageNum(currPage);
            result.setPageSize(pageSize);
            redisUtil.set(key, result);
        }

        return result;
    }

    @Override
    public PageInfo queryCourseByKeyWordByPage(int currPage, int pageSize, String keyWord, Integer status) {
        if (status == null) {
            status = 2;
        }

        validStatus(status);

        PageHelper.startPage(currPage, pageSize);

        PageInfo<CourseVo> result = new PageInfo<>(transToVo(courseDao.queryByKeyWords(keyWord, status)));

        return result;
    }

    @Override
    public CourseVo queryById(Integer id, Integer status) {
        List<Course> courses = new ArrayList<>();
        Course course = courseDao.queryById(id, status);

        if (ObjectUtils.isEmpty(course)) {
            throw new CustomException(ExceptionEnums.CUSTOM_ERROR.getCode(),
                    "无该课程");
        }

        courses.add(course);
//        User loginUser = UserContext.getLoginUser();
//        Integer userId = loginUser.getId();
        List<History> historyList = historyService.queryCourseHistoryByCurrUser(id);

        List<CourseChapterVo> courseChapterVos = courseChapterService.queryChaptersByCourseId(id);
        Integer detailNumber = 0; //课程下小节的数量
        for (CourseChapterVo courseChapterVo : courseChapterVos) {
            //获取小节的数量
            detailNumber += courseChapterVo.getChildren().size();
        }
        CourseVo courseVo = transToVo(courses).get(0);
        Integer progress = 0;
        if (detailNumber == 0) {
            courseVo.setProgress(0);
        } else {
            for (History history : historyList) {
                progress += history.getProgress();
            }
            Integer totalProgress = progress / (detailNumber * 100);
            courseVo.setProgress(totalProgress);
        }
        return courseVo;
    }

    @Override
    public PageInfo queryCourseByType(int currPage, int pageSize, Integer typeId, Integer status) {


        if (status == null) {
            status = 2;
        }

        validStatus(status);

        Page page = PageHelper.startPage(currPage, pageSize);

        List<Integer> typeIds = courseTypeService.queryChildType(typeId);

        PageInfo<CourseVo> result = new PageInfo<>(transToVo(courseDao.queryCourseByType(typeIds, status)));

        result.setTotal(page.getTotal());
        result.setPageSize(pageSize);
        result.setPageNum(currPage);

        return result;

    }

    @Override
    public Integer queryCourseCount() {
        return courseDao.queryCourseCount();
    }

    @Override
    public List<CourseVo> queryCourseNew() {
        return transToVo(courseDao.queryCourseNew());
    }

    @Override
    public List<CourseVo> queryCourseLevel(String level) {
        List<Integer> levels = Arrays.asList(level.split(",")).stream().map(Integer::parseInt).collect(Collectors.toList());
        return transToVo(courseDao.queryCourseByLevel(levels));
    }

    @Override
    public List<CourseVo> queryCourseFront() {
        Integer typeId = courseTypeService.queryTypeByKeyword("前沿");
        return transToVo(courseDao.queryCourseFront(typeId));
    }


    /**
     * 将Course model转换为Coursevo
     *
     * @param courses
     * @return
     */
    private List<CourseVo> transToVo(List<Course> courses) {

        List<CourseVo> result = new ArrayList<>();
        for (Course course : courses) {
            CourseVo courseVo = new CourseVo.Builder()
                    .setId(course.getId())
                    .setClassName(course.getClassName())
                    .setCoverPath(course.getCoverPath())
                    .setIntroduction(course.getIntroduction())
                    .setTeacher(course.getTeacher().equals("admin") ? "官方" : course.getTeacher())
                    .setLevel(CourseLevelEnums.getLevelDescByLevel(course.getLevel()))
                    .setScore(course.getScore())
                    .setScoreUser(course.getScoreUser())
                    .setStudyNumber(course.getStudyNumber())
                    .setStatus(course.getStatus())
                    .setType(courseTypeService.queryCourseTypeName(course.getTypeId()))
                    .setCreateTime(course.getCreateTime())
                    .setBaseKnowledge(course.getBaseKnowledge())
                    .setLearn(course.getLearn())
                    .setTypeIds(course.getTypeId())
                    .setLevelCode(course.getLevel())
                    .build();

            result.add(combinationCourseVo(courseVo));
        }
        return result;

    }

    /**
     * 验证status参数
     *
     * @param status
     */
    private void validStatus(Integer status) {
        if (status != null) {
            if (status < 1 || status > 5) {
                throw new CustomException(ExceptionEnums.CUSTOM_ERROR.getCode(),
                        "参数status[" + status + "]错误");
            }
        }
    }

    /**
     * 组合返回结果
     *
     * @param courseVo
     * @return
     */
    private CourseVo combinationCourseVo(CourseVo courseVo) {
        List<CourseChapterVo> courseChapters = courseChapterService.queryChaptersByCourseId(courseVo.getId());
        return courseVo.setCourseChapterVos(courseChapters);

    }
}
